package client;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Random;

import config.Config;

public class Client extends Thread {
	Socket socket;
	BufferedReader in;
	PrintWriter out;
	
	ArrayList<Result> result;
	int minutes;
	int clientID;
	long startTime;
	long stopTime;
	String middle_man_host;
	
	public Socket getSocket() {
		return socket;
	}
	
	public Client(int _minutes, int _clientID, String _middle_man_host) {
		result = new ArrayList<Result>();
		minutes = _minutes;
		clientID = _clientID;
		middle_man_host = _middle_man_host;
		connect();
	}
	
	public ArrayList<Result> getResult() {
		return result;
	}
	
	protected void runQuery(String queryName, String sql) {
		//System.err.println("Client " + clientID + " - " + queryName + " => starting...");
		
		sql = sql.replaceAll("\\n", "NEWLINE");
		String fromServer;
		long start = System.currentTimeMillis();
		try {
			// Send the query to the Middle Man
			out.println(sql);
			
			// Receive the result from the Middle Man
			fromServer = in.readLine();
			
			long stop = System.currentTimeMillis();
			
			System.err.println("Client " + clientID + " - " + queryName + " => " + (stop - start) + " ms" + " => " + fromServer);
			
			// If the query execution was OK, we should have an Y as a result
			if(fromServer != null && fromServer.startsWith("SUCCESS")) {
				result.add(new Result(clientID, queryName, start, stop, true));
			} else {
				result.add(new Result(clientID, queryName, start, stop, false));
			}
		} catch (IOException e) {
			System.err.println("Client " + clientID + " - exception: " + e.getMessage());
			//e.printStackTrace();
		}
	}
	
	public void run() {
		System.err.println("Client " + clientID + " running...");
		startTime = System.currentTimeMillis();
		int currentQuery = new Random().nextInt(22);
		long milliseconds = ((long)minutes) * 60 * 1000;
		while(true) {
			if(System.currentTimeMillis() - startTime > milliseconds) {
				break;
			}
			runQuery("Q" + Config.queries_execution_order[currentQuery], FastQueryGenerator.Q(Config.queries_execution_order[currentQuery]));
			currentQuery ++;
			if(currentQuery > 21) {
				currentQuery = 0;
			}
		}
		stopTime = System.currentTimeMillis();
		double running_minutes = ((double)(stopTime - startTime)) / (1000 * 60);
		long actual_running_minutes = (long)running_minutes;
		System.err.println("Client " + clientID + " done, ran for " + actual_running_minutes + " minutes");
		disconnect();
	}
	
	protected void connect() { 
		socket = null;
		try {
			socket = new Socket(middle_man_host, Config.middle_man_port);
			in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			out = new PrintWriter(socket.getOutputStream(), true);
		} catch (UnknownHostException e) {
			System.err.println("Client " + clientID + " could not connect: Unknown host " + middle_man_host);
			e.printStackTrace();
		} catch (IOException e) {
			System.err.println("Client " + clientID + " could not connect: IO Error");
			e.printStackTrace();
		}
	}
	
	protected void disconnect() {
		try {
			out.close();
			in.close();
			socket.close();
		} catch (IOException e1) {
			System.err.println("Client " + clientID + " did not disconnect successfully.");
			e1.printStackTrace();
		}
	}
}
